package com.zan.zanchat.common.common.service;

import com.zan.zanchat.common.common.exception.BusinessException;
import com.zan.zanchat.common.common.exception.CommonErrorEnum;
import lombok.SneakyThrows;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @Author Zan
 * @Create 2024/3/17 14:35
 * @Description :
 */
@Service
public class LockService {

    @Resource
    private RedissonClient redissonClient;

    /**
     *
     * @param key
     * @param waitTime
     * @param timeUnit
     * @param supplier 只有入参，没有出参
     * @return
     * @param <T>
     */
    @SneakyThrows // 忽略异常
    public <T> T executeWithLock(String key, int waitTime, TimeUnit timeUnit, Supplier<T> supplier) {
        RLock lock = redissonClient.getLock(key);
        boolean successLock = lock.tryLock(waitTime, timeUnit);
//        AssertUtil.isTrue(successLock, CommonErrorEnum.LOCK_LIMIT);
        if (!successLock) {
            // 加锁失败
            throw new BusinessException(CommonErrorEnum.LOCK_LIMIT);
        }
        try {
            // 具体逻辑
            return supplier.get();
        } finally {
            lock.unlock();
        }
    }

    public <T> T executeWithLock(String key, Supplier<T> supplier) {
        return executeWithLock(key, -1, TimeUnit.MILLISECONDS, supplier);
    }

    public <T> T executeWithLock(String key, Runnable runnable) {
        return executeWithLock(key, -1, TimeUnit.MILLISECONDS, () -> {
            runnable.run();
            return null;
        });
    }

    /**
     * 由于内部Java底层的Supplier的get()方法没有抛出异常，因此需要自定义一个Supplier，抛出异常
     * @param <T>
     */
    @FunctionalInterface
    public interface Supplier<T> {
        T get() throws Throwable;
    }
}
